#!/usr/bin/env php
<?php
/**************************************************************************
 *
 *   Copyright 2010 American Public Media Group
 *
 *   This file is part of AIR2.
 *
 *   AIR2 is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   AIR2 is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with AIR2.  If not, see <http://www.gnu.org/licenses/>.
 *
 *************************************************************************/

require_once 'Test.php';
require_once 'app/init.php';
require_once 'AirHttpTest.php';
require_once 'models/TestSource.php';
require_once 'models/TestUser.php';
require_once 'models/TestBatch.php';

// set up the table(s)
AIR2_DBManager::init();

// init browser
$browser = new AirHttpTest();
$browser->set_test_user();
$browser->set_content_type(AirHttpTest::$JSON); // set to json
$conn = AIR2_DBManager::get_master_connection();

// create some dummy data
$b1 = new TestBatch();
$b1->save();
$b2 = new TestBatch();
$b2->save();
$s1 = new TestSource();
$s1->save();
$s2 = new TestSource();
$s2->save();
$s3 = new TestSource();
$s3->save();
$s4 = new TestSource();
$s4->save();
$s5 = new TestSource();
$s5->save();
$s6 = new TestSource();
$s6->save();
$u1 = new TestUser();
$u1->save();
$u2 = new TestUser();
$u2->save();
$u3 = new TestUser();
$u3->save();

plan(118);

/**********************
 * access batch, checking that count is 0
 */
$uuid = $b1->batch_uuid;
ok( $resp = $browser->http_get('/batch/'.$uuid), 'GET batch' );
is( $browser->resp_code(), 200, "GET batch response code" );
ok( $json = json_decode($resp,true), "JSON decode GET batch" );
is( $json['radix']['batch_count'], 0, 'batch count initially 0' );
isnt( $json['radix']['batch_last_use'], null, 'batch last use initially set' );


/**********************
 * check for response codes on 'contents'
 */
$browser->http_get('/batch/'.$uuid.'/contents');
is( $browser->resp_code(), 200, 'GET batch/123/contents 200' );
$browser->http_post('/batch/'.$uuid.'/contents');
is( $browser->resp_code(), 405, 'POST batch/123/contents 405' );
$browser->http_delete('/batch/'.$uuid.'/contents');
is( $browser->resp_code(), 405, 'DELETE batch/123/contents 405' );
$browser->http_put('/batch/'.$uuid.'/contents');
is( $browser->resp_code(), 200, 'PUT batch/123/contents 200' );


/**********************
 * check batch multiple-ADD functionality (PUT)
 */
$add1 = array( array('type'=>'S', 'uuid'=>$s1->src_uuid), array('type'=>'S', 'uuid'=>$s2->src_uuid),
    array('type'=>'S', 'uuid'=>$s3->src_uuid), array('type'=>'S', 'uuid'=>$s4->src_uuid) );
$add2 = array( array('type'=>'S', 'uuid'=>$s6->src_uuid), array('type'=>'S', 'uuid'=>$s3->src_uuid),
    array('type'=>'S', 'uuid'=>$s4->src_uuid), array('type'=>'S', 'uuid'=>$s5->src_uuid) );
$adduser = array( array('type'=>'U', 'uuid'=>$u1->user_uuid),
    array('type'=>'U', 'uuid'=>$u2->user_uuid), array('type'=>'U', 'uuid'=>$u3->user_uuid) );
$data1 = array('add' => json_encode($add1));
$data2 = array('add' => json_encode($add2));
$data3 = array('add' => json_encode(array(array('type'=>'S', 'uuid'=>'BADUUID1'), array('type'=>'S', 'uuid'=>'BADUUID2'))));
$datauser = array('add' => json_encode($adduser));

// failure of adding to non-existent batch
ok( $resp = $browser->http_put('/batch/0010/contents', $data1), 'PUT-add to non-existent batch' );
is( $browser->resp_code(), 404, "PUT-add to non-existant batch resp code" );

// add 4 items to batch
ok( $resp = $browser->http_put('/batch/'.$uuid.'/contents', $data1), 'PUT-add to batch' );
is( $browser->resp_code(), 200, "PUT-add to batch resp code" );
ok( $json = json_decode($resp,true), "JSON decode PUT-add" );
is( $json['radix']['batch_count'], 4, 'PUT-add batch count = 4' );
ok( $json['radix']['batch_last_use'], 'PUT-add batch last use' );
$use_dtim = $json['radix']['batch_last_use'];

// add overlapping items to batch
ok( $resp = $browser->http_put('/batch/'.$uuid.'/contents', $data2), 'PUT-add overlap to batch' );
is( $browser->resp_code(), 200, "PUT-add overlap resp code" );
ok( $json = json_decode($resp,true), "JSON decode PUT-add overlap" );
is( $json['radix']['batch_count'], 6, 'PUT-add overlap count = 6' );
ok( $json['radix']['batch_last_use'] >= $use_dtim, 'PUT-add overlap last use' );
$use_dtim = $json['radix']['batch_last_use'];

// add bad UUID's
ok( $resp = $browser->http_put('/batch/'.$uuid.'/contents', $data3), 'PUT-add bad UUIDs' );
is( $browser->resp_code(), 200, "PUT-add bad UUIDs resp code" );
ok( $json = json_decode($resp,true), "JSON decode PUT-add bad UUIDs" );
is( $json['radix']['batch_count'], 6, 'PUT-add bad UUIDs count = 6' );
ok( $json['radix']['batch_last_use'] == $use_dtim, 'PUT-add bad UUIDs last use' );

// add to a batch with an unknown type
$b1->batch_type = '?';
$b1->save();
ok( $resp = $browser->http_put('/batch/'.$uuid.'/contents', $data3), 'PUT-add bad type' );
is( $browser->resp_code(), 200, "PUT-add bad type resp code" );
ok( $json = json_decode($resp,true), "JSON decode PUT-add bad type" );
is( $json['success'], false, 'PUT-add bad type unsuccess' );
ok( $json['message'], 'PUT-add bad type message' );

// add a User to a batch
$conn->execute('delete from batch_item where bitem_batch_id = ?', array($b1->batch_id));
$b1->batch_type = 'U';
$b1->save();
ok( $resp = $browser->http_put('/batch/'.$uuid.'/contents', $datauser), 'PUT-add users to batch' );
is( $browser->resp_code(), 200, "PUT-add users to batch resp code" );
ok( $json = json_decode($resp,true), "JSON decode PUT-add users" );
is( $json['radix']['batch_count'], 3, 'PUT-add users batch count = 3' );
ok( $json['radix']['batch_last_use'], 'PUT-add users batch last use' );
$conn->execute('delete from batch_item where bitem_batch_id = ?', array($b1->batch_id));
$b1->batch_type = 'S';
$b1->save();


/**********************
 * test merging a batch
 */
$uuid2 = $b2->batch_uuid;
// setup batches to merge
ok( $resp = $browser->http_put('/batch/'.$uuid.'/contents', $data1), 'DUP batch setup' );
is( $browser->resp_code(), 200, "DUP batch resp code" );
ok( $json = json_decode($resp,true), "JSON decode DUP batch" );
is( $json['radix']['batch_count'], 4, 'DUP batch count = 4' );

ok( $resp = $browser->http_put('/batch/'.$uuid2.'/contents', $data2), 'DUP2 batch setup' );
is( $browser->resp_code(), 200, "DUP2 batch resp code" );
ok( $json = json_decode($resp,true), "JSON decode DUP2 batch" );
is( $json['radix']['batch_count'], 4, 'DUP2 batch count = 4' );

// create the new batch to duplicate into
$b3 = new TestBatch();
$b3->save();
$dup_uuid = $b3->batch_uuid;
ok( $resp = $browser->http_get("/batch/$dup_uuid"), 'DUP3 GET' );
is( $browser->resp_code(), 200, "DUP3 resp-code" );
ok( $json = json_decode($resp,true), "JSON decode DUP3" );
is( $json['radix']['batch_uuid'], $dup_uuid, "JSON DUP3 get uuid" );
is( $json['radix']['batch_count'], 0, "JSON DUP3 count 0" );

// merge the first batch into this new batch
$merge = array('merge' => json_encode(array($uuid)));
ok( $resp = $browser->http_put('/batch/'.$dup_uuid.'/contents', $merge), 'DUP batch merge' );
is( $browser->resp_code(), 200, "DUP batch merge resp code" );
ok( $json = json_decode($resp,true), "JSON decode DUP batch merge" );
is( $json['radix']['batch_count'], 4, 'DUP batch merge batch count = 4' );

// merge a bunch of duplicates into batch, and check the count
$merge = array('merge' => json_encode(array($uuid, $uuid2)));
ok( $resp = $browser->http_put('/batch/'.$dup_uuid.'/contents', $merge), 'DUP batch merge 2' );
is( $browser->resp_code(), 200, "DUP batch merge 2 resp code" );
ok( $json = json_decode($resp,true), "JSON decode DUP batch merge 2" );
is( $json['radix']['batch_count'], 6, 'DUP batch merge 2 batch count = 6' );


/**********************
 * test removing from a batch
 */
$rmv = array('remove' => json_encode(array(
    array('type'=>'S', 'uuid'=>$s1->src_uuid),
    array('type'=>'S', 'uuid'=>$s3->src_uuid),
)));
ok( $resp = $browser->http_put('/batch/'.$dup_uuid.'/contents', $rmv), 'REMOVE batch' );
is( $browser->resp_code(), 200, "REMOVE batch resp code" );
ok( $json = json_decode($resp,true), "JSON decode REMOVE batch" );
is( $json['radix']['batch_count'], 4, 'REMOVE batch count = 4' );

// remove same items again --- should have no effect
ok( $resp = $browser->http_put('/batch/'.$dup_uuid.'/contents', $rmv), 'REMOVE again batch' );
is( $browser->resp_code(), 200, "REMOVE again batch resp code" );
ok( $json = json_decode($resp,true), "JSON decode REMOVE again batch" );
is( $json['radix']['batch_count'], 4, 'REMOVE again batch count = 4' );


/**********************
 * test removing ALL from a batch
 */
ok( $resp = $browser->http_put('/batch/'.$dup_uuid.'/contents', array('removeall'=>true)), 'REMOVE all batch' );
is( $browser->resp_code(), 200, "REMOVE all batch resp code" );
ok( $json = json_decode($resp,true), "JSON decode REMOVE all batch" );
is( $json['radix']['batch_count'], 0, 'REMOVE all batch count = 0' );

// remove ALL, with exclusions (should give a batch_count > 0)
$excl = json_encode(array(array('type'=>'S', 'uuid'=>$s1->src_uuid)));
ok( $resp = $browser->http_put('/batch/'.$dup_uuid.'/contents', $data1), 'REMOVE all exclusions setup' );
is( $browser->resp_code(), 200, "REMOVE all exclusions setup resp code" );
ok( $json = json_decode($resp,true), "JSON decode REMOVE all exclusions setup" );
is( $json['radix']['batch_count'], 4, 'REMOVE all exclusions setup count = 4' );
ok( $resp = $browser->http_put('/batch/'.$dup_uuid.'/contents', array('removeall'=>$excl)), 'REMOVE all exclusions' );
is( $browser->resp_code(), 200, "REMOVE all exclusions resp code" );
ok( $json = json_decode($resp,true), "JSON decode REMOVE all exclusions" );
is( $json['radix']['batch_count'], 1, 'REMOVE all exclusions count = 1' );


/**********************
 * test adding a search to a batch
 */
$conn->execute('delete from batch_item where bitem_batch_id = ?', array($b1->batch_id));

// get the total count for a search
ok( $resp = $browser->http_get('/search?i=sources&q=test&limit=1'), 'Search find total');
is( $browser->resp_code(), 200, "Search find total resp code" );
ok( $json = json_decode($resp,true), "JSON decode Search find total" );
$total = isset($json['total']) ? $json['total'] : null;
ok( $total && $total > 0, "Search find total has total ($total)" );

// check that adding the search produces the same number
$params = json_encode(array(
    'q' => 'test',
    'i' => 'sources',
    'total' => $total,
));
$addsearch = array('addsearch' => $params);
ok( $resp = $browser->http_put('/batch/'.$uuid.'/contents', $addsearch), 'ADD search' );
is( $browser->resp_code(), 200, "ADD search resp code" );
ok( $json = json_decode($resp,true), "JSON decode ADD search" );

// determine if the dbconv has run, based on source table count
$num = $conn->fetchOne('select count(*) from source', array(), 0);
if ($num <= 6) todo_start("SEARCH INDEXES OUT-OF-SYNC with source table");
is( $json['radix']['batch_count'], $total, "ADD search count = $total" );
if ($num <= 6) todo_end();

// test having the count change during the server-side search
$params2 = json_encode(array(
    'q' => 'test',
    'i' => 'sources',
    'total' => $total + 10,
));
$addsearch2 = array('addsearch' => $params2);
ok( $resp = $browser->http_put('/batch/'.$uuid.'/contents', $addsearch2), 'ADD bad-count search' );
is( $browser->resp_code(), 200, "ADD bad-count search resp code" );
ok( $json = json_decode($resp,true), "JSON decode ADD bad-count search" );
is( $json['success'], false, "ADD bad-count search unsuccessful" );

// test adding items to the wrong batch type
$b1->batch_type = 'U';
$b1->save();
ok( $resp = $browser->http_put('/batch/'.$uuid.'/contents', $addsearch), 'ADD bad-type search' );
is( $browser->resp_code(), 200, "ADD bad-type search resp code" );
ok( $json = json_decode($resp,true), "JSON decode ADD bad-type search" );
is( $json['success'], false, "ADD bad-type search unsuccessful" );



/**********************
 * test randomly splitting a batch
 */
$big_count = 100000;
// cleanup
$name = $b1->batch_name;
$conn->execute("delete from batch where batch_name like '$name %'", array());
$conn->execute('delete from batch_item where bitem_batch_id = ?', array($b1->batch_id));

//setup --- process 10K at a time (to avoid insert buffer errors)
$flds = 'bitem_batch_id, bitem_type, bitem_xid, bitem_status, bitem_cre_user, bitem_cre_dtim';
$dtim = air2_date();
$type = $b1->batch_type;
$bid = $b1->batch_id;
for ($big=0; $big<($big_count/10000); $big++) {
    $items = '';
    $base = 10000 * $big;
    for ($i=0; $i<10000; $i++) {
        if (strlen($items) > 0) $items .= ", ";
        $xid = $i + $base;
        $items .= "($bid,'$type',$xid,'A',1,'$dtim')";
    }
    $conn->execute("insert into batch_item ($flds) values $items", array());
}

// check the item count
ok( $resp = $browser->http_get("/batch/$uuid"), 'random setup GET' );
is( $browser->resp_code(), 200, "random setup resp-code" );
ok( $json = json_decode($resp,true), "JSON decode random setup" );
is( $json['radix']['batch_count'], $big_count, "JSON random setup count = $big_count" );

// get 1 random batch of size 5834
$rand = array('random' => json_encode(array('size'=>5834)));
ok( $resp = $browser->http_put('/batch/'.$uuid.'/contents', $rand), 'random 5834 batch' );
is( $browser->resp_code(), 200, "random 5834 batch resp code" );
ok( $json = json_decode($resp,true), "JSON decode random 5834 batch" );
is( count($json['radix']), 1, 'random 5834 batch returned 1 batch' );
is( $json['radix'][0]['batch_count'], 5834, 'random 5834 batch count correct' );

// GET the size of the random batch
$rand_uuid = $json['radix'][0]['batch_uuid'];
ok( $resp = $browser->http_get("/batch/$rand_uuid"), 'random 5834 count GET' );
is( $browser->resp_code(), 200, "random 5834 count resp-code" );
ok( $json = json_decode($resp,true), "JSON decode random 5834 count" );
is( $json['radix']['batch_count'], 5834, "JSON random 5834 count is 5834" );

// get 2 random batches of size 525
$rand = array('random' => json_encode(array('numbatches'=>2,'size'=>525)));
ok( $resp = $browser->http_put('/batch/'.$uuid.'/contents', $rand), 'random 525 batch' );
is( $browser->resp_code(), 200, "random 525 batch resp code" );
ok( $json = json_decode($resp,true), "JSON decode random 525 batch" );
is( count($json['radix']), 2, 'random 525 batch returned 2 batches' );
is( $json['radix'][0]['batch_count'], 525, 'random 525 batch count 1 correct' );
is( $json['radix'][1]['batch_count'], 525, 'random 525 batch count 2 correct' );

// check that the contents don't overlap
$rand_uuid1 = $json['radix'][0]['batch_uuid'];
$rand_uuid2 = $json['radix'][1]['batch_uuid'];
$rand_id1 = $conn->fetchOne("select batch_id from batch where batch_uuid = ?", array($rand_uuid1), 0);
$rand_id2 = $conn->fetchOne("select batch_id from batch where batch_uuid = ?", array($rand_uuid2), 0);
$count = $conn->fetchOne("select count(*) from (select bitem_id from batch_item ".
    "where bitem_batch_id = $rand_id1 and bitem_xid in (select bitem_xid from ".
    "batch_item where bitem_batch_id = $rand_id2)) a", array(), 0);
is( $count, 0, "random 525 contents don't overlap" );

// split the batch into 11 subbatches
$rand = array('random' => json_encode(array('numbatches'=>11)));
ok( $resp = $browser->http_put('/batch/'.$uuid.'/contents', $rand), 'random 11 batch' );
is( $browser->resp_code(), 200, "random 11 batch resp code" );
ok( $json = json_decode($resp,true), "JSON decode random 11 batch" );
is( count($json['radix']), 11, 'random 11 batch returned 11 batches' );
$rand_total = 0;
foreach ($json['radix'] as $rand_batch) {
    $rand_total += $rand_batch['batch_count'];
}
is( $rand_total, $big_count, "random 11 batch counts add up to $big_count" );


// cleanup the random batches
$name = $b1->batch_name;
$conn->execute("delete from batch where batch_name like '$name %'", array());

?>
